package EventLoopTest.Test001;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.nio.charset.StandardCharsets;
import java.util.Date;

public class NettyTimeServer {
    
    private final int port;
    
    public NettyTimeServer(int port) {
        this.port = port;
    }
    
    public void run() throws Exception {
        // 1. 创建线程组
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);   // 接受连接
        EventLoopGroup workerGroup = new NioEventLoopGroup();  // 处理IO
        
        try {
            // 2. 创建服务器启动引导
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                     .channel(NioServerSocketChannel.class)    // 使用NIO传输
                     .childHandler(new ChannelInitializer<SocketChannel>() {
                         @Override
                         protected void initChannel(SocketChannel ch) {
                             // 3. 配置处理管道
                             ChannelPipeline pipeline = ch.pipeline();
                             
                             // 解决粘包/拆包问题
                             pipeline.addLast(new LineBasedFrameDecoder(1024));
                             
                             // 字符串编解码器
                             pipeline.addLast(new StringDecoder(StandardCharsets.UTF_8));
                             pipeline.addLast(new StringEncoder(StandardCharsets.UTF_8));
                             
                             // 业务处理器
                             pipeline.addLast(new TimeServerHandler());
                         }
                     })
                     .option(ChannelOption.SO_BACKLOG, 128)    // 连接队列大小
                     .childOption(ChannelOption.SO_KEEPALIVE, true); // 保持连接
            
            // 4. 绑定端口并启动服务器
            ChannelFuture future = bootstrap.bind(port).sync();
            System.out.println("时间服务器启动，监听端口: " + port);
            
            // 5. 等待服务器通道关闭
            future.channel().closeFuture().sync();
            
        } finally {
            // 6. 优雅关闭
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
    
    // 业务处理器
    private static class TimeServerHandler extends ChannelInboundHandlerAdapter {
        
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            String request = (String) msg;
            System.out.println("收到请求: " + request);
            
            String response;
            if ("time".equalsIgnoreCase(request.trim())) {
                response = "当前时间: " + new Date() + "\n";
            } else if ("timestamp".equalsIgnoreCase(request.trim())) {
                response = "时间戳: " + System.currentTimeMillis() + "\n";
            } else {
                response = "未知命令，支持: time, timestamp\n";
            }
            
            // 异步写入响应
            ChannelFuture future = ctx.writeAndFlush(response);
            
            // 如果需要关闭连接
            if ("quit".equalsIgnoreCase(request.trim())) {
                future.addListener(ChannelFutureListener.CLOSE);
            }
        }
        
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            cause.printStackTrace();
            ctx.close();
        }
        
        @Override
        public void channelActive(ChannelHandlerContext ctx) {
            System.out.println("客户端连接: " + ctx.channel().remoteAddress());
        }
        
        @Override
        public void channelInactive(ChannelHandlerContext ctx) {
            System.out.println("客户端断开: " + ctx.channel().remoteAddress());
        }
    }
    
    public static void main(String[] args) throws Exception {
        int port = 8888;
        new NettyTimeServer(port).run();
    }
}